package com.cv.framework.websocket.core.handler;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.TypeUtil;
import com.cv.framework.common.utils.json.JsonUtil;
import com.cv.framework.websocket.core.listener.WebSocketMessageListener;
import com.cv.framework.websocket.core.message.JsonWebSocketMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * JSON WebSocket 消息处理器
 *
 * @author Charles_XDXD
 */
@Slf4j
public class JsonWebSocketMessageHandler extends TextWebSocketHandler {

    private final Map<String, WebSocketMessageListener<Object>> listeners = new HashMap<>();

    @SuppressWarnings({"unchecked", "rawtypes"})
    public JsonWebSocketMessageHandler(List<? extends WebSocketMessageListener> listenerList) {
        listenerList.forEach(listener -> listeners.put(listener.getType(), listener));
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 如果发送的消息为空，则直接跳过
        if (message.getPayloadLength() == 0) {
            return;
        }

        // ping 心跳消息，返回 pong
        if (message.getPayloadLength() == 4 && Objects.equals(message.getPayload(), "ping")) {
            session.sendMessage(new TextMessage("pong"));
            return;
        }

        // 解析消息
        try {
            JsonWebSocketMessage jsonWebSocketMessage = JsonUtil.parseObject(message.getPayload(), JsonWebSocketMessage.class);
            if (ObjUtil.isEmpty(jsonWebSocketMessage)) {
                log.error("[handleTextMessage][session({}) message({})] 无法解析消息为 JsonWebSocketMessage 对象", session.getId(), message.getPayload());
                return;
            }

            if (StrUtil.isEmpty(jsonWebSocketMessage.getType())) {
                log.error("[handleTextMessage][session({}) message({}) 类型为空]", session.getId(), message.getPayload());
                return;
            }

            WebSocketMessageListener<Object> listener = listeners.get(jsonWebSocketMessage.getType());
            if (ObjUtil.isEmpty(listener)) {
                log.error("[handleTextMessage][session({}) message({})] 无法找到对应的消息处理器", session.getId(), message.getPayload());
                return;
            }

            // 处理消息
            Type type = TypeUtil.getTypeArgument(listener.getClass(), 0);
            Object messageObject = JsonUtil.parseObject(jsonWebSocketMessage.getContent(), type);
            listener.onMessage(session, messageObject);
        } catch (Throwable ex) {
            log.error("[handleTextMessage][session({}) message({})] 处理消息异常", session.getId(), message.getPayload(), ex);
        }
    }

}
